import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * Class <code>StatementCoverTable</code> 
 */
public class StatementCoverageTable {

	/** mStatementLineMap[i] means the line number in source code */
	private Map<Integer, Integer> mStatementLineMap = new HashMap<Integer, Integer>();
	
	/** Line Number to Suspiciousness */
	private  ArrayList< Pair<Integer,Double> > mStatementSuspicious = new ArrayList< Pair<Integer,Double> >();

	/** Statement Cover Table: nnStatementCoverTable[i][j] is the number of test case i that excute statement j */
	private ArrayList<ArrayList<Integer>> nnStatementCoverTable = new ArrayList<ArrayList<Integer>>();
	
	private ISuspiciousnessCalculator suspiciousnessCalculator
	= new HeuristicIII();
	
	
	public void setSuspiciousnessCalculator(ISuspiciousnessCalculator newSuspiciousnessCalculator)
	{
		suspiciousnessCalculator = newSuspiciousnessCalculator;
	}
	
	
	/**
	 * Initialize mStatementLineMap and llStatementCoverTable using Arff Stream.
	 * 
	 * @param istArff .Arff Input Stream
	 * @return void
	 * @throws IOException
	 */
	public void readFromArff(InputStream istArff) throws IOException {


		BufferedReader brArff = 
			new BufferedReader(new InputStreamReader(istArff));

		brArff.readLine();

		int nLineCounter = 0;
		

		/* Init the mStatementLineMap */
		Pattern pStatementLineNumber = Pattern
				.compile("@ATTRIBUTE \\d+ NUMERIC");
		for (String sArffLine = brArff.readLine(); 
		sArffLine != null && pStatementLineNumber.matcher(sArffLine).matches(); 
		sArffLine = brArff.readLine()) {

			Pattern pNum = Pattern.compile("[@a-zA-Z ]+");
			int nSourceLineNumber = Integer.parseInt(pNum.split(sArffLine)[1]);
			mStatementLineMap.put(nLineCounter, nSourceLineNumber);
			nLineCounter++;
			
		}

		brArff.readLine();

		/* Init the llStatementCoverTable */
		for (String sArffLine = brArff.readLine(); sArffLine != null;
		sArffLine = brArff.readLine()) {
			Pattern pSplitResult = Pattern.compile(",");
			String[] sarrStatement = pSplitResult.split(sArffLine);
			
			
			
			ArrayList<Integer> nStatementCoverRow = new ArrayList<Integer>();			
			
			for(int i=0;i<sarrStatement.length-1;i++){
				nStatementCoverRow.add(Integer.parseInt(sarrStatement[i]));				
			}
			nStatementCoverRow.add(sarrStatement[sarrStatement.length-1].trim().equalsIgnoreCase("passed")?0:1);
			
			nnStatementCoverTable.add(nStatementCoverRow);
			
		}

	}

	public void calcSuspiciousness(){

		ArrayList<Double> darrSuspiciousnessTable ;
		darrSuspiciousnessTable = suspiciousnessCalculator.calcSuspiciousness(nnStatementCoverTable);
		
		for(int i = 0 ; i < darrSuspiciousnessTable.size();i++){
			mStatementSuspicious.add(new Pair(mStatementLineMap.get(i),darrSuspiciousnessTable.get(i)));			
		}
	}

	public void clear(){
		mStatementLineMap.clear();
		mStatementSuspicious.clear();
		nnStatementCoverTable.clear();
		
	}

	public void printSuspiciousness(PrintStream psOut){
		
		//System.err.format("LineNum\tSuspicious%n");
		
		Collections.sort( mStatementSuspicious, new Comparator<Pair<Integer,Double>>() {

			@Override
			public int compare(Pair<Integer,Double> o1, Pair<Integer,Double> o2) {
				return - o1.getSecond().compareTo( o2.getSecond());
			}
			
		});
		
		for(int i = 0 ; i < mStatementSuspicious.size();i++){
			psOut.format("%d\t%f%n",
					mStatementSuspicious.get(i).getFirst(),
					mStatementSuspicious.get(i).getSecond());	
		}
		psOut.println();
		
	}

}
